home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Tool Chest / Development Tools & Languages / Dylan Related / Mindy / Mindy 1.2 - portable sources / interp / thread.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-15  |  17.4 KB  |  786 lines  |  [TEXT/ttxt]

  1. /**********************************************************************\
  2. *
  3. *  Copyright (c) 1994  Carnegie Mellon University
  4. *  All rights reserved.
  5. *  
  6. *  Use and copying of this software and preparation of derivative
  7. *  works based on this software are permitted, including commercial
  8. *  use, provided that the following conditions are observed:
  9. *  
  10. *  1. This copyright notice must be retained in full on any copies
  11. *     and on appropriate parts of any derivative works.
  12. *  2. Documentation (paper or online) accompanying any system that
  13. *     incorporates this software, or any part of it, must acknowledge
  14. *     the contribution of the Gwydion Project at Carnegie Mellon
  15. *     University.
  16. *  
  17. *  This software is made available "as is".  Neither the authors nor
  18. *  Carnegie Mellon University make any warranty about the software,
  19. *  its performance, or its conformity to any specification.
  20. *  
  21. *  Bug reports, questions, comments, and suggestions should be sent by
  22. *  E-mail to the Internet address "gwydion-bugs@cs.cmu.edu".
  23. *
  24. ***********************************************************************
  25. *
  26. * $Header: thread.c,v 1.21 94/10/05 21:04:42 nkramer Exp $
  27. *
  28. * This file implements threads, and the various synchronization
  29. * primitives.
  30. *
  31. \**********************************************************************/
  32.  
  33. #include "../compat/std-c.h"
  34.  
  35. #include "mindy.h"
  36. #include "gc.h"
  37. #include "bool.h"
  38. #include "class.h"
  39. #include "thread.h"
  40. #include "obj.h"
  41. #include "driver.h"
  42. #include "func.h"
  43. #include "num.h"
  44. #include "list.h"
  45. #include "def.h"
  46. #include "type.h"
  47. #include "error.h"
  48.  
  49. #define STACK_SIZE (1*1024*1024)
  50.  
  51. static struct thread_list *AllThreads = NULL;
  52. static struct thread_list **AllThreadsTail = &AllThreads;
  53. static int NextId = 0;
  54.  
  55. static struct thread *Current = NULL;
  56. static struct thread *Runnable = NULL;
  57.  
  58. static obj_t obj_ThreadClass, obj_LockClass, obj_SpinLockClass, obj_EventClass;
  59.  
  60. static void remove_from_lock(struct thread *thread);
  61. static void add_to_lock(struct thread *thread);
  62. static void remove_from_event(struct thread *thread);
  63.  
  64.  
  65.  
  66. struct thread_list *all_threads(void)
  67. {
  68.     return AllThreads;
  69. }
  70.  
  71.  
  72.  
  73. /* Scheduling stuff. */
  74.  
  75. struct thread *thread_current()
  76. {
  77.     return Current;
  78. }
  79.  
  80. static obj_t dylan_current_thread()
  81. {
  82.     return Current->thread_obj;
  83. }
  84.  
  85. void thread_set_current(struct thread *thread)
  86. {
  87.     Current = thread;
  88. }
  89.  
  90. struct thread *thread_pick_next()
  91. {
  92.     struct thread *thread = Runnable;
  93.  
  94.     if (thread)
  95.     Runnable = thread->next;
  96.  
  97.     Current = thread;
  98.  
  99.     return thread;
  100. }
  101.  
  102.  
  103. /* Utilities. */
  104.  
  105. static void set_status(struct thread *thread, enum thread_status status)
  106. {
  107.     thread->status = status;
  108.     THREAD(thread->thread_obj)->status = status;
  109. }
  110.  
  111. static void suspend_thread(struct thread *thread)
  112. {
  113.     if (thread == Runnable) {
  114.     if (thread == thread->next)
  115.         Runnable = NULL;
  116.     else {
  117.         Runnable = thread->next;
  118.         *thread->prev = Runnable;
  119.         Runnable->prev = thread->prev;
  120.     }
  121.     }
  122.     else {
  123.     *thread->prev = thread->next;
  124.     thread->next->prev = thread->prev;
  125.     }
  126.  
  127.     thread->next = NULL;
  128.     thread->prev = NULL;
  129. }
  130.  
  131. static void wakeup_thread(struct thread *thread)
  132. {
  133.     if (thread->suspend_count == 0) {
  134.     if (Runnable) {
  135.         thread->next = Runnable;
  136.         thread->prev = Runnable->prev;
  137.         *thread->prev = thread;
  138.         Runnable->prev = &thread->next;
  139.     }
  140.     else {
  141.         thread->next = thread;
  142.         thread->prev = &thread->next;
  143.         Runnable = thread;
  144.     }
  145.     set_status(thread, status_Running);
  146.     }
  147.     else
  148.     set_status(thread, status_Suspended);
  149. }
  150.  
  151. static void return_false(struct thread *thread)
  152. {
  153.     obj_t *old_sp = pop_linkage(thread);
  154.  
  155.     *old_sp = obj_False;
  156.     thread->sp = old_sp + 1;
  157.  
  158.     do_return(thread, old_sp, old_sp);
  159. #if SLOW_LONGJMP
  160.     go_on();
  161. #endif
  162. }
  163.  
  164. static void stop_thread(struct thread *thread, obj_t *vals)
  165. {
  166.     obj_t thread_obj = thread->thread_obj;
  167.  
  168.     assert(Current == thread);
  169.  
  170.     thread_kill(thread);
  171.  
  172.     THREAD(thread_obj)->status = status_Exited;
  173.  
  174.     pause(pause_PickNewThread);
  175. }
  176.  
  177. static void start_thread(struct thread *thread)
  178. {
  179.     obj_t *old_sp = obj_rawptr(thread->datum);
  180.  
  181.     thread->advance = NULL;
  182.     thread->datum = obj_False;
  183.  
  184.     invoke(thread, (thread->sp - old_sp) - 1);
  185. }
  186.  
  187.  
  188. /* Thread creation. */
  189.  
  190. struct thread *thread_create(obj_t debug_name)
  191. {
  192.     obj_t thread_obj = alloc(obj_ThreadClass, sizeof(struct thread_obj));
  193.     struct thread_list *list = malloc(sizeof(*list));
  194.     struct thread *thread = malloc(STACK_SIZE);
  195.  
  196.     THREAD(thread_obj)->thread = thread;
  197.     THREAD(thread_obj)->debug_name = debug_name;
  198.  
  199.     list->thread = thread;
  200.     list->next = NULL;
  201.     *AllThreadsTail = list;
  202.     AllThreadsTail = &list->next;
  203.  
  204.     thread->thread_obj = thread_obj;
  205.     thread->id = NextId++;
  206.     thread->next = NULL;
  207.     thread->prev = NULL;
  208.     thread->suspend_count = 1;
  209.     thread->advance = start_thread;
  210.     set_status(thread, status_Suspended);
  211.     thread->datum = rawptr_obj(thread+1);
  212.     thread->stack_base = (obj_t *)(thread+1);
  213.     thread->stack_end = (obj_t *)(((char *)thread) + STACK_SIZE);
  214.     thread->sp = thread->stack_base;
  215.     thread->fp = NULL;
  216.     thread->component = 0;
  217.     thread->pc = 0;
  218.     thread->cur_catch = obj_False;
  219.     thread->cur_uwp = NULL;
  220.     thread->handlers = obj_False;
  221.  
  222.     set_c_continuation(thread, stop_thread);
  223.  
  224.     return thread;
  225. }
  226.  
  227. static obj_t dylan_spawn_thread(obj_t debug_name, obj_t func)
  228. {
  229.     struct thread *thread = thread_create(debug_name);
  230.  
  231.     *thread->sp++ = func;
  232.  
  233.     thread_restart(thread);
  234.  
  235.     return thread->thread_obj;
  236. }
  237.  
  238.  
  239.  
  240. /* Pushing escape frames. */
  241.  
  242. static void pop_escape_frame(struct thread *thread, obj_t *vals)
  243. {
  244.     thread->sp = vals;
  245.     thread_pop_escape(thread);
  246. }
  247.  
  248. void thread_push_escape(struct thread *thread)
  249. {
  250.     switch (thread->status) {
  251.       case status_Running:
  252.     suspend_thread(thread);
  253.     break;
  254.  
  255.       case status_Suspended:
  256.     *thread->sp++ = make_fixnum(thread->suspend_count);
  257.     break;
  258.  
  259.       case status_Debuggered:
  260.     break;
  261.  
  262.       case status_Blocked:
  263.     remove_from_lock(thread);
  264.     break;
  265.  
  266.       case status_Waiting:
  267.     remove_from_event(thread);
  268.     break;
  269.  
  270.       default:
  271.     lose("strange thread status.");
  272.     }
  273.  
  274.     *thread->sp++ = thread->datum;
  275.     *thread->sp++ = make_fixnum((int)thread->status);
  276.     *thread->sp++ = rawptr_obj(thread->advance);
  277.     *thread->sp++ = thread->component;
  278.     *thread->sp++ = make_fixnum(thread->pc);
  279.  
  280.     thread->advance = start_thread;
  281.     set_status(thread, status_Suspended);
  282.     thread->suspend_count = 1;
  283.     thread->datum = rawptr_obj(thread->sp);
  284.     set_c_continuation(thread, pop_escape_frame);
  285. }
  286.  
  287. void thread_pop_escape(struct thread *thread)
  288. {
  289.     thread->pc = fixnum_value(*--thread->sp);
  290.     thread->component = *--thread->sp;
  291.     thread->advance = obj_rawptr(*--thread->sp);
  292.     set_status(thread, (enum thread_status)fixnum_value(*--thread->sp));
  293.     thread->datum = *--thread->sp;
  294.     
  295.     switch (thread->status) {
  296.       case status_Running:
  297.     break;
  298.  
  299.       case status_Suspended:
  300.     suspend_thread(thread);
  301.     thread->suspend_count = fixnum_value(*--thread->sp);
  302.     break;
  303.  
  304.       case status_Debuggered:
  305.     suspend_thread(thread);
  306.     break;
  307.  
  308.       case status_Blocked:
  309.     add_to_lock(thread);
  310.     break;
  311.  
  312.       case status_Waiting:
  313.     set_status(thread, status_Running);
  314.     break;
  315.  
  316.       default:
  317.     lose("strange thread status.");
  318.     }
  319. }
  320.  
  321.  
  322. /* Thread destruction */
  323.  
  324. void thread_kill(struct thread *thread)
  325. {
  326.     struct thread_list *list, **prev;
  327.  
  328.     switch (thread->status) {
  329.       case status_Running:
  330.     suspend_thread(thread);
  331.     break;
  332.       case status_Suspended:
  333.       case status_Debuggered:
  334.     break;
  335.       case status_Blocked:
  336.     remove_from_lock(thread);
  337.     break;
  338.       case status_Waiting:
  339.     remove_from_event(thread);
  340.     break;
  341.  
  342.       default:
  343.     lose("strange thread status.");
  344.     }
  345.  
  346.     for (prev = &AllThreads; (list = *prev) != NULL; prev = &list->next) {
  347.     if (list->thread == thread) {
  348.         struct thread_list *next = list->next;
  349.         *prev = next;
  350.         if (next == NULL)
  351.         AllThreadsTail = prev;
  352.         free(list);
  353.         break;
  354.     }
  355.     }
  356.     assert(list != NULL);
  357.  
  358.     if (Current == thread)
  359.     Current = NULL;
  360.  
  361.     THREAD(thread->thread_obj)->thread = NULL;
  362.     THREAD(thread->thread_obj)->status = status_Killed;
  363.  
  364.     free(thread);
  365. }
  366.  
  367. static obj_t dylan_kill_thread(obj_t thread_obj)
  368. {
  369.     struct thread *thread = THREAD(thread_obj)->thread;
  370.     boolean me = (thread == Current);
  371.  
  372.     thread_kill(thread);
  373.  
  374.     if (me)
  375.     pause(pause_PickNewThread);
  376.  
  377.     return thread_obj;
  378. }
  379.     
  380.  
  381.  
  382. /* Thread suspending and restarting. */
  383.  
  384. void thread_debuggered(struct thread *thread, obj_t condition)
  385. {
  386.     assert(thread == Current);
  387.  
  388.     suspend_thread(thread);
  389.     set_status(thread, status_Debuggered);
  390.     thread->datum = condition;
  391.     pause(pause_DebuggerInvoked);
  392. }
  393.  
  394. void thread_buggered(struct thread *thread)
  395. {
  396.     if (thread->status != status_Debuggered)
  397.     lose("Trying to bugger a thread that wasn't originally Debuggered?");
  398.     else {
  399.     wakeup_thread(thread);
  400.     set_status(thread, status_Running);
  401.     thread->datum = obj_False;
  402.     }
  403. }
  404.  
  405. void thread_suspend(struct thread *thread)
  406. {
  407.     if (thread->suspend_count++ == 0 && thread->status == status_Running) {
  408.     suspend_thread(thread);
  409.     set_status(thread, status_Suspended);
  410.     }
  411. }
  412.  
  413. void thread_restart(struct thread *thread)
  414. {
  415.     if (thread->suspend_count > 0) {
  416.     thread->suspend_count--;
  417.     if (thread->suspend_count == 0 && thread->status == status_Suspended)
  418.         wakeup_thread(thread);
  419.     }
  420. }
  421.  
  422.  
  423.  
  424. /* Locks */
  425.  
  426. struct lock {
  427.     obj_t class;
  428.     boolean locked;
  429.     struct thread *waiting;
  430.     struct thread **last;
  431. };
  432.  
  433. #define LOCK(o) obj_ptr(struct lock *, o)
  434.  
  435. obj_t make_lock(void)
  436. {
  437.     obj_t res = alloc(obj_SpinLockClass, sizeof(struct lock));
  438.  
  439.     LOCK(res)->locked = FALSE;
  440.     LOCK(res)->waiting = NULL;
  441.     LOCK(res)->last = &LOCK(res)->waiting;
  442.  
  443.     return res;
  444. }
  445.  
  446. boolean lock_query(obj_t lock)
  447. {
  448.     return LOCK(lock)->locked;
  449. }
  450.  
  451. static obj_t dylan_lock_query(obj_t lock)
  452. {
  453.     if (lock_query(lock))
  454.     return obj_True;
  455.     else
  456.     return obj_False;
  457. }
  458.  
  459. void lock_grab(struct thread *thread, obj_t lock,
  460.            void (*advance)(struct thread *thread))
  461. {
  462.     if (LOCK(lock)->locked) {
  463.     suspend_thread(thread);
  464.     *LOCK(lock)->last = thread;
  465.     LOCK(lock)->last = &thread->next;
  466.     thread->next = NULL;
  467.     thread->prev = NULL;
  468.     set_status(thread, status_Blocked);
  469.     thread->datum = lock;
  470.     thread->advance = advance;
  471.  
  472.     pause(pause_PickNewThread);
  473.     }
  474.     else {
  475.     LOCK(lock)->locked = TRUE;
  476.     advance(thread);
  477.     }
  478. }
  479.  
  480. static obj_t dylan_lock_grab(obj_t lock)
  481. {
  482.     lock_grab(Current, lock, return_false);
  483.     /* lock_grab doesn't return. */
  484.     lose("lock_grab actually returned?");
  485.     return NULL;
  486. }
  487.  
  488. void lock_release(obj_t lock)
  489. {
  490.     struct thread *waiting = LOCK(lock)->waiting;
  491.  
  492.     if (waiting != NULL) {
  493.     struct thread *next = waiting->next;
  494.  
  495.     LOCK(lock)->waiting = next;
  496.     if (next == NULL)
  497.         LOCK(lock)->last = &LOCK(lock)->waiting;
  498.     wakeup_thread(waiting);
  499.     waiting->datum = obj_False;
  500.     }
  501.     else
  502.     LOCK(lock)->locked = FALSE;
  503. }
  504.  
  505. static obj_t dylan_lock_release(obj_t lock)
  506. {
  507.     if (!LOCK(lock)->locked)
  508.     error("%= is already unlocked.", lock);
  509.  
  510.     lock_release(lock);
  511.  
  512.     return obj_False;
  513. }
  514.  
  515. static void remove_from_lock(struct thread *thread)
  516. {
  517.     obj_t lock = thread->datum;
  518.     struct thread *scan, **prev;
  519.  
  520.     prev = &LOCK(lock)->waiting;
  521.     while (1) {
  522.     scan = *prev;
  523.     if (scan == NULL)
  524.         lose("Tried to remove a thread from an lock it "
  525.          "wasn't waiting on.");
  526.     if (scan == thread) {
  527.         *prev = thread->next;
  528.         if (thread->next == NULL)
  529.         LOCK(lock)->last = prev;
  530.         return;
  531.     }
  532.     }
  533. }
  534.  
  535. static void add_to_lock(struct thread *thread)
  536. {
  537.     obj_t lock = thread->datum;
  538.  
  539.     if (LOCK(lock)->locked) {
  540.     suspend_thread(thread);
  541.     *LOCK(lock)->last = thread;
  542.     LOCK(lock)->last = &thread->next;
  543.     thread->next = NULL;
  544.     thread->prev = NULL;
  545.     }
  546.     else {
  547.     LOCK(lock)->locked = TRUE;
  548.     thread->datum = obj_False;
  549.     }
  550. }
  551.  
  552.  
  553. /* Events. */
  554.  
  555. struct event {
  556.     obj_t class;
  557.     struct thread *waiting;
  558.     struct thread **last;
  559. };
  560.  
  561. #define EVENT(o) obj_ptr(struct event *, o)
  562.  
  563. obj_t make_event(void)
  564. {
  565.     obj_t res = alloc(obj_EventClass, sizeof(struct event));
  566.     
  567.     EVENT(res)->waiting = NULL;
  568.     EVENT(res)->last = &EVENT(res)->waiting;
  569.  
  570.     return res;
  571. }
  572.  
  573. void event_wait(struct thread *thread, obj_t event, obj_t lock,
  574.         void (*advance)(struct thread *thread))
  575. {
  576.     if (lock != obj_False && !LOCK(lock)->locked)
  577.     error("%= is already unlocked.", lock);
  578.  
  579.     suspend_thread(thread);
  580.     *EVENT(event)->last = thread;
  581.     EVENT(event)->last = &thread->next;
  582.     thread->prev = NULL;
  583.     thread->next = NULL;
  584.     set_status(thread, status_Waiting);
  585.     thread->datum = event;
  586.     thread->advance = advance;
  587.  
  588.     if (lock != obj_False)
  589.     lock_release(lock);
  590.  
  591.     pause(pause_PickNewThread);
  592. }    
  593.  
  594. static obj_t dylan_event_wait(obj_t event, obj_t lock)
  595. {
  596.     event_wait(Current, event, lock, return_false);
  597.     /* event_wait doesn't return. */
  598.     lose("event_wait actually returned?\n");
  599.     return NULL;
  600. }
  601.  
  602. obj_t event_signal(obj_t event)
  603. {
  604.     struct thread *waiting;
  605.  
  606.     waiting = EVENT(event)->waiting;
  607.  
  608.     if (waiting != NULL) {
  609.     struct thread *next = waiting->next;
  610.  
  611.     EVENT(event)->waiting = next;
  612.     if (next == NULL)
  613.         EVENT(event)->last = &EVENT(event)->waiting;
  614.     wakeup_thread(waiting);
  615.     waiting->datum = obj_False;
  616.     }
  617.  
  618.     return obj_False;
  619. }
  620.  
  621. obj_t event_broadcast(obj_t event)
  622. {
  623.     struct thread *waiting;
  624.     
  625.     waiting = EVENT(event)->waiting;
  626.  
  627.     while (waiting != NULL) {
  628.     struct thread *next = waiting->next;
  629.  
  630.     wakeup_thread(waiting);
  631.     waiting->datum = obj_False;
  632.  
  633.     waiting = next;
  634.     }
  635.     EVENT(event)->waiting = NULL;
  636.     EVENT(event)->last = &EVENT(event)->waiting;
  637.  
  638.     return obj_False;
  639. }
  640.  
  641. static void remove_from_event(struct thread *thread)
  642. {
  643.     obj_t event = thread->datum;
  644.     struct thread *scan, **prev;
  645.  
  646.     prev = &EVENT(event)->waiting;
  647.     while (1) {
  648.     scan = *prev;
  649.     if (scan == NULL)
  650.         lose("Tried to remove a thread from an event it "
  651.          "wasn't waiting on.");
  652.     if (scan == thread) {
  653.         *prev = thread->next;
  654.         if (thread->next == NULL)
  655.         EVENT(event)->last = prev;
  656.         thread->datum = obj_False;
  657.         return;
  658.     }
  659.     }
  660. }
  661.  
  662.  
  663. /* GC stuff. */
  664.  
  665. static int scav_thread_obj(struct object *o)
  666. {
  667.     struct thread_obj *t = (struct thread_obj *)o;
  668.  
  669.     scavenge(&t->debug_name);
  670.  
  671.     return sizeof(struct thread_obj);
  672. }
  673.  
  674. static obj_t trans_thread_obj(obj_t t)
  675. {
  676.     return transport(t, sizeof(struct thread_obj));
  677. }
  678.  
  679. static int scav_lock(struct object *o)
  680. {
  681.     struct lock *lock = (struct lock *)o;
  682.  
  683.     if (lock->waiting == NULL)
  684.     lock->last = &lock->waiting;
  685.  
  686.     return sizeof(struct lock);
  687. }
  688.  
  689. static obj_t trans_lock(obj_t lock)
  690. {
  691.     return transport(lock, sizeof(struct lock));
  692. }
  693.  
  694. static int scav_event(struct object *o)
  695. {
  696.     struct event *event = (struct event *)o;
  697.  
  698.     if (event->waiting == NULL)
  699.     event->last = &event->waiting;
  700.  
  701.     return sizeof(struct event);
  702. }
  703.  
  704. static obj_t trans_event(obj_t event)
  705. {
  706.     return transport(event, sizeof(struct event));
  707. }
  708.  
  709. static void scav_thread(struct thread *thread)
  710. {
  711.     obj_t *ptr;
  712.  
  713.     scavenge(&thread->thread_obj);
  714.     scavenge(&thread->datum);
  715.     scavenge(&thread->component);
  716.     scavenge(&thread->cur_catch);
  717.     scavenge(&thread->handlers);
  718.  
  719.     for (ptr = thread->stack_base; ptr < thread->sp; ptr++)
  720.     scavenge(ptr);
  721.     memset(thread->sp, 0, (thread->stack_end - thread->sp) * sizeof(obj_t));
  722. }
  723.  
  724. void scavenge_thread_roots(void)
  725. {
  726.     struct thread_list *list;
  727.  
  728.     for (list = AllThreads; list != NULL; list = list->next)
  729.     scav_thread(list->thread);
  730.  
  731.     scavenge(&obj_ThreadClass);
  732.     scavenge(&obj_LockClass);
  733.     scavenge(&obj_SpinLockClass);
  734.     scavenge(&obj_EventClass);
  735. }
  736.  
  737.  
  738. /* Init stuff. */
  739.  
  740. void make_thread_classes(void)
  741. {
  742.     obj_ThreadClass = make_builtin_class(scav_thread_obj, trans_thread_obj);
  743.     obj_LockClass = make_abstract_class(FALSE);
  744.     obj_SpinLockClass = make_builtin_class(scav_lock, trans_lock);
  745.     obj_EventClass = make_builtin_class(scav_event, trans_event);
  746. }
  747.  
  748. void init_thread_classes(void)
  749. {
  750.     init_builtin_class(obj_ThreadClass, "<thread>", obj_ObjectClass, NULL);
  751.     init_builtin_class(obj_LockClass, "<lock>", obj_ObjectClass, NULL);
  752.     init_builtin_class(obj_SpinLockClass, "<spinlock>", obj_LockClass, NULL);
  753.     init_builtin_class(obj_EventClass, "<event>", obj_ObjectClass, NULL);
  754. }
  755.  
  756. void init_thread_functions(void)
  757. {
  758.     define_function("spawn-thread", list2(obj_ObjectClass, obj_FunctionClass),
  759.             FALSE, obj_False, FALSE, obj_ThreadClass,
  760.             dylan_spawn_thread);
  761.     define_function("current-thread", obj_Nil, FALSE, obj_False, FALSE,
  762.             obj_ThreadClass, dylan_current_thread);
  763.     define_function("kill-thread", list1(obj_ThreadClass), FALSE, obj_False,
  764.             FALSE, obj_ThreadClass, dylan_kill_thread);
  765.  
  766.     define_method("make", list1(singleton(obj_LockClass)), FALSE, obj_Nil,
  767.           FALSE, obj_SpinLockClass, make_lock);
  768.     define_method("make", list1(singleton(obj_SpinLockClass)), FALSE, obj_Nil,
  769.           FALSE, obj_SpinLockClass, make_lock);
  770.     define_method("locked?", list1(obj_SpinLockClass), FALSE, obj_False,
  771.           FALSE, obj_BooleanClass, dylan_lock_query);
  772.     define_method("grab-lock", list1(obj_SpinLockClass), FALSE, obj_False,
  773.           FALSE, obj_ObjectClass, dylan_lock_grab);
  774.     define_method("release-lock", list1(obj_SpinLockClass), FALSE, obj_False,
  775.           FALSE, obj_ObjectClass, dylan_lock_release);
  776.  
  777.     define_method("make", list1(singleton(obj_EventClass)), FALSE, obj_Nil,
  778.           FALSE, obj_EventClass, make_event);
  779.     define_method("wait-for-event", list2(obj_EventClass, obj_SpinLockClass),
  780.           FALSE, obj_False, FALSE, obj_ObjectClass, dylan_event_wait);
  781.     define_method("signal-event", list1(obj_EventClass),
  782.           FALSE, obj_False, FALSE, obj_ObjectClass, event_signal);
  783.     define_method("broadcast-event", list1(obj_EventClass),
  784.           FALSE, obj_False, FALSE, obj_ObjectClass, event_broadcast);
  785. }
  786.